#include "client.h"
static void send_train(int sockfd, char buf[], int len){
    train_t train;
    memset(&train, 0, sizeof(train));
    train.length = len;
    memcpy(&train, buf, len);
    send(sockfd, &train, sizeof(int)+train.length, MSG_NOSIGNAL);
}
//客户端puts，上传文件给服务端
int PUTS_Client(int sockfd, cmdInfo_t *cmdinfo){
    //第 001 步，客户端先获取自己要上传的文件有多大，直接读磁盘
    //注意事项，参考百度网盘，上传，肯定是上传本地的文件，所以是本地路径
    //所以不用cmfInfo里面的cmdpath,而是用命令行arg
    //第 001 小步骤，打开待上传的文件对应的文件描述符
    if (strlen(cmdinfo->arg) == 0) {
        printf("puts 命令的参数有误！没有指定文件\n");
        return -1;
    }

    int fd = open(cmdinfo->arg, O_RDONLY);
    printf("fd = %d\n", fd);
    if(fd == -1){
        printf("打开文件 %s 失败！\n", cmdinfo->arg);
        return -1;
    }
    //第 002 小步骤，创建stat结构体，方便用fstat函数获取打开的fd文件
    //获取目标文件大小，将其放进cmdinfo命令结构体相应的fileSize里面
    struct stat statbuf;
    fstat(fd, &statbuf);
    cmdinfo->fileSize = statbuf.st_size;
    printf("cmdinfo->fileSize = %ld\n", cmdinfo->fileSize);
    close(fd);//及时关闭

    //第 003 小步骤，在客户端计算文件的MD5哈希值，也放进cmdinfo命令结构中
    char buf[1024];
    printf("cmdinfo->arg = %s\n", cmdinfo->arg);
    // 使用cmdinfo->arg来构造命令字符串
    char command[256]; // 假设命令的总长度不会超过255个字符加上终止符
    snprintf(command, sizeof(command), "sha1sum %s", cmdinfo->arg);
    printf("command = %s\n", command);
    //command[strlen(command)] = '\0';
    // 使用格式化好的命令打开管道
    FILE *pipe = popen(command, "r");
    fread(buf, 1, sizeof(buf), pipe);
    printf("hash: %s", buf);
    char *buf999;
    buf999 = strtok(buf, " ");
    printf("buf999 = %s\n", buf999);
    printf("buf = %s\n", buf);
    memcpy(cmdinfo->md5, buf, strlen(buf)+1);
    printf("md5 = %s\n", cmdinfo->md5);
    pclose(pipe);

    //第 004 小步骤，能走到这里，表示客户端确实传的是文件，同时也存在
    //所以，把arg参数直接切割到最后，得到该文件的具体文件名，放进cmdinfo命令结构体中
    char *p;
    char duplicate[100] = {0};
    strcpy(duplicate, cmdinfo->arg);
    p = strtok(duplicate," /");
    char *lastToken = NULL;
    while(p != NULL){
        lastToken = p;
        p = strtok(NULL, "/");
    }
    if(lastToken != NULL){
        memcpy(cmdinfo->fileName, lastToken, strlen(lastToken)+1);
        printf("选择上传的文件是 %s\n", cmdinfo->fileName);
    }else{
        cmdinfo->fileName[0] = '\0';
        printf("请选定具体文件！\n");
        return -1;
    }
    printf("切割后，cmdinfo->fileSize = %ld\n", cmdinfo->fileSize);
    printf("cmdinfo->fileName = %s\n", cmdinfo->fileName);

    //第 002 步，经典小火车，把这一坨命令结构发送过去，本次函数出现第 1 次发送
    train_t train;
    memset(&train, 0, sizeof(train_t));
    train.length = sizeof(cmdInfo_t);
    memcpy(train.data, cmdinfo, train.length);
    send(sockfd, &train, sizeof(int)+train.length, MSG_NOSIGNAL);
    printf("文件名相关命令已经发送给服务端！\n");

    //第 3 步，接收服务端发过来的信息，确定是否实现秒传，秒传就直接退出了
    memset(&train, 0, sizeof(train));
    recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
    int ret = recv(sockfd, train.data, train.length, MSG_WAITALL);
    //进行判断，是继续往前走，还是已经实现秒传，当场结束？
    if(ret == 3 && strcmp(train.data, "ok") == 0){
        printf("上传成功！此次上传用时 1 秒！\n");
        return 0;
    }else if(strcmp(train.data, "no!") == 0){
        printf("上传失败！\n");
        return -1;
    }else if(strcmp(train.data, "warning") == 0){
        printf("上传失败，文件名重复！\n");
        return -1;
    }

    //第 4 步，正式开始发送文件，本次函数出现第 2 次发送，直接进入senFile函数
    ret = sendFile(sockfd, cmdinfo);
    printf("sendFile ret = %d\n", ret);

    //接收是否完成，走到这里，肯定能接收
    memset(&train, 0, sizeof(train));
    recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
    recv(sockfd, train.data, train.length, MSG_WAITALL);
    printf("train.data = %s\n", train.data);
    if(strcmp(train.data, "ojbk!") == 0){
        printf("收到 ojbk!\n");
        printf("上传成功！\n");
        return 0;
    }
    return 0;
}
//客户端 gets 下载文件到客户端
int GETS_Client(int sockfd, cmdInfo_t *cmdinfo){
    //第 001 步，先判断命令是否有效？
    if(strlen(cmdinfo->arg) == 0){
        printf("请输入要下载文件！\n");
        return -1;
    }

    //再判断 arg 是不是有效文件路径名
    char *p;
    char duplicate[100] = {0};
    strcpy(duplicate, cmdinfo->arg);
    p = strtok(duplicate," /");
    char *lastToken = NULL;
    while(p != NULL){
        lastToken = p;
        p = strtok(NULL, "/");
    }
    if(lastToken != NULL){
        memcpy(cmdinfo->fileName, lastToken, strlen(lastToken)+1);
        printf("选择下载的文件是 %s\n", cmdinfo->fileName);
    }else{                                                                                                                                
        cmdinfo->fileName[0] = '\0';
        printf("请选定具体文件！\n");
        return -1;
    }
    printf("pcmdinfo->fileSize = %ld\n", cmdinfo->fileSize);
    printf("pcmdinfo->fileName = %s\n", cmdinfo->fileName);
    
    //第 002 步，经典发送命令一坨过去cmdInfo_t *cmdinfo
    train_t train;
    memset(&train, 0, sizeof(train));
    train.length = sizeof(cmdInfo_t);
    memcpy(train.data, cmdinfo, train.length);
    send(sockfd, &train, sizeof(int)+train.length, MSG_NOSIGNAL);

    //接收服务端发来的信息，确定是否能下载，再往后走，或者当场退出
    memset(&train, 0, sizeof(train));
    recv(sockfd, &train.length, sizeof(int), MSG_WAITALL);
    recv(sockfd, train.data, train.length, MSG_WAITALL);
    if(strcmp(train.data, "-1") == 0){
        printf("该输入有效文件名！\n");
        return -1;
    }
    else if(strcmp(train.data, "-2") == 0){
        printf("输入的是目录，请输入有效文件名！\n");
        return -1;
    }
    else{
        printf("准备下载！\n");
    }
    //继续往下走
    int ret = recvFile(sockfd, cmdinfo);
    if(ret == -1){
        printf("下载失败！\n");
        return -1;
    }
    return 0;
}

